/**
 * @file container.c
 * @author lishuaiming
 * @brief
 * @version 0.1
 * @date 2024-03-04
 * 容器相关
 * @copyright Copyright (c) 2024
 *
 */
#include "container.h"
#include "docker.h"

/// @brief 向上级发送进度
/// @param code
/// @param progress
/// @return
bool send_progress_V3(int code, int progress, ST_IOTA_LOG_RES *progressDecs)
{
    cJSON *json = NULL;
    cJSON *body = NULL;
    char *pcJson;
    json = cJSON_CreateObject();
    body = cJSON_CreateObject();
    char cTime[128] = {0};
    int ret = systemDate2(cTime);
    if (progressDecs)
    {
        // json
        cJSON_AddStringToObject(json, "mid", progressDecs->iMid);
        cJSON_AddNumberToObject(json, "code", code);
        cJSON_AddStringToObject(json, "deviceSn", progressDecs->deviceSn);
        cJSON_AddStringToObject(json, "replyId", progressDecs->replyId);
        cJSON_AddStringToObject(json, "zone", progressDecs->zone);
        cJSON_AddStringToObject(json, "node", progressDecs->node);
        // cJSON_AddStringToObject(json, "requestId", progressDecs->requestID);
        cJSON_AddStringToObject(json, "msgTime", cTime);
        cJSON_AddStringToObject(json, "deviceId", progressDecs->deviceID);
        cJSON_AddNumberToObject(json, "installProgress", progress);
        pcJson = cJSON_PrintUnformatted(json);
        ret = IOTA_SendMqtt("/v1/devices/virtualization/response", pcJson, strlen(pcJson));
        dzlog_debug("code = %d progress = %d", code, progress);
        cJSON_Delete(json);
        free_s(pcJson);
        return true;
    }
    else
    {
        return false;
    }
}

bool JsonToStruct_ContainerInstall(char *pcJson, ST_IOTA_LOG *pcStatusDecs)
{
    cJSON *json = NULL;
    cJSON *param = NULL;
    int i = 0;
    json = cJSON_Parse(pcJson);
    if (json)
    {
        pcStatusDecs->iMid = strdup(cJSON_GetObjectItem(json, "mid")->valuestring);
        pcStatusDecs->deviceSn = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        pcStatusDecs->Servicename = strdup(cJSON_GetObjectItem(json, "service")->valuestring);
        pcStatusDecs->zone = strdup(cJSON_GetObjectItem(json, "zone")->valuestring);
        pcStatusDecs->node = strdup(cJSON_GetObjectItem(json, "node")->valuestring);
        // if (cJSON_HasObjectItem(json, "requestId") && strlen(cJSON_GetObjectItem(json, "requestId")->valuestring) > 0)
        //{
        //     pcStatusDecs->requestID = strdup(cJSON_GetObjectItem(json, "requestId")->valuestring);
        // }
        // else
        //{
        //     pcStatusDecs->requestID = NULL;
        // }
        pcStatusDecs->msgTime = strdup(cJSON_GetObjectItem(json, "msgTime")->valuestring);
        pcStatusDecs->deviceID = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);

        if (cJSON_HasObjectItem(json, "params"))
        {
            param = cJSON_GetObjectItem(json, "params");
            IOTA_CONTAINER_INFO *st_param = pcStatusDecs->param;
            st_param->containerId = strdup(cJSON_GetObjectItem(param, "containerId")->valuestring);
            st_param->containerName = strdup(cJSON_GetObjectItem(param, "containerName")->valuestring);
            st_param->containerHyperv = strdup(cJSON_GetObjectItem(param, "containerHyperv")->valuestring);
            st_param->fileId = strdup(cJSON_GetObjectItem(param, "fileId")->valuestring);

            if (cJSON_HasObjectItem(param, "cpuCount"))
            {
                st_param->cpuCount = cJSON_GetObjectItem(param, "cpuCount")->valueint;
            }
            else
            {
                st_param->cpuCount = 0;
            }

            if (cJSON_HasObjectItem(param, "cpuPeriod"))
            {
                st_param->cpuPeriod = cJSON_GetObjectItem(param, "cpuPeriod")->valueint;
            }
            else
            {
                st_param->cpuPeriod = 0;
            }

            if (cJSON_HasObjectItem(param, "cpuQuota"))
            {
                st_param->cpuQuota = cJSON_GetObjectItem(param, "cpuQuota")->valueint;
            }
            else
            {
                st_param->cpuQuota = 0;
            }

            if (cJSON_HasObjectItem(param, "memorySize"))
            {
                st_param->memorySize = cJSON_GetObjectItem(param, "memorySize")->valueint;
            }
            else
            {
                st_param->memorySize = 0;
            }

            if (cJSON_HasObjectItem(param, "storageSize"))
            {
                st_param->storageSize = cJSON_GetObjectItem(param, "storageSize")->valueint;
            }
            else
            {
                st_param->storageSize = 0;
            }

            if (cJSON_HasObjectItem(param, "srcContainerId"))
            {
                st_param->srcContainerId = cJSON_GetObjectItem(param, "srcContainerId")->valuestring;
            }
            else
            {
                st_param->srcContainerId = NULL;
            }

            if (cJSON_HasObjectItem(param, "srcContainerName"))
            {
                st_param->srcContainerName = cJSON_GetObjectItem(param, "srcContainerName")->valuestring;
            }
            else
            {
                st_param->srcContainerName = NULL;
            }

            st_param->imageName = strdup(cJSON_GetObjectItem(param, "imageName")->valuestring);

            if (cJSON_HasObjectItem(param, "imageTag"))
            {
                st_param->imageTag = cJSON_GetObjectItem(param, "imageTag")->valuestring;
            }
            else
            {
                st_param->imageTag = NULL;
            }

            if (cJSON_HasObjectItem(param, "devices"))
            {
                cJSON *devices = cJSON_GetObjectItem(param, "devices");
                int array_size = cJSON_GetArraySize(devices);
                st_param->devicecount = array_size;
                st_param->devices = malloc(sizeof(container_devices_map) * array_size + 1);

                for (i = 0; i < array_size; i++)
                {
                    cJSON *map = cJSON_GetArrayItem(devices, i);
                    char *key = strtok(map->valuestring, ":");
                    char *value = strtok(NULL, ":");
                    strcpy(st_param->devices[i].key, key);
                    strcpy(st_param->devices[i].value, value);
                }
            }
            else
            {
                st_param->devices = NULL;
            }

            if (cJSON_HasObjectItem(param, "volumes"))
            {
                cJSON *volumes = cJSON_GetObjectItem(param, "volumes");
                int array_size = cJSON_GetArraySize(volumes);
                st_param->volumecount = array_size;
                st_param->volumes = malloc(sizeof(container_volumn) * array_size + 1);

                for (i = 0; i < array_size; i++)
                {
                    cJSON *volumn = cJSON_GetArrayItem(volumes, i);
                    if (cJSON_HasObjectItem(volumn, "path"))
                    {
                        strcpy(st_param->volumes[i].path, cJSON_GetObjectItem(volumn, "path")->valuestring);
                    }
                    else
                    {
                        memset(st_param->volumes[i].path, 0, sizeof(st_param->volumes[i].path));
                    }
                    st_param->volumes[i].size = cJSON_GetObjectItem(volumn, "size")->valueint;
                    st_param->volumes[i].visible = cJSON_GetObjectItem(volumn, "visible")->valueint;
                }
            }
            else
            {
                st_param->volumes = NULL;
            }
            if (cJSON_HasObjectItem(param, "ip"))
            {
                st_param->ip = strdup(cJSON_GetObjectItem(param, "ip")->valuestring);
            }
            else
            {
                st_param->ip = NULL;
            }
        }
        cJSON_Delete(json);
        return true;
    }
    else
    {
        return false;
    }
}

int StructToJson_ContainerInstallRes(char **pcJson, ST_IOTA_LOG_RES *pcStatusDecs)
{
    if (pcStatusDecs)
    {
        cJSON *json = NULL;
        cJSON *body = NULL;
        json = cJSON_CreateObject();
        body = cJSON_CreateObject();
        char cTime[128] = {0};
        int ret = systemDate2(cTime);
        // json
        cJSON_AddStringToObject(json, "mid", pcStatusDecs->iMid);
        cJSON_AddNumberToObject(json, "code", pcStatusDecs->code);
        cJSON_AddStringToObject(json, "deviceSn", pcStatusDecs->deviceSn);
        cJSON_AddStringToObject(json, "replyId", pcStatusDecs->replyId);
        cJSON_AddStringToObject(json, "zone", pcStatusDecs->zone);
        cJSON_AddStringToObject(json, "node", pcStatusDecs->node);
        // cJSON_AddStringToObject(json, "requestId", pcStatusDecs->requestID);
        cJSON_AddStringToObject(json, "msgTime", cTime);
        cJSON_AddStringToObject(json, "deviceId", pcStatusDecs->deviceID);

        // body
        IOTA_CONTAINER_RES *st_body = (IOTA_CONTAINER_RES *)pcStatusDecs->body;
        cJSON_AddStringToObject(body, "containerId", st_body->containerId);
        if (st_body->srcContainerId != NULL)
        {
            cJSON_AddStringToObject(body, "srcContainerId", st_body->srcContainerId);
        }

        cJSON_AddItemToObject(json, "body", body);
        *pcJson = cJSON_PrintUnformatted(json);

        cJSON_Delete(json);
        return true;
    }
    else
    {
        return false;
    }
}
bool JsonToStruct_ContainerCtrl(char *pcJson, ST_IOTA_LOG *pcStatusDecs)
{
    cJSON *json = NULL;
    cJSON *param = NULL;
    int i = 0;
    json = cJSON_Parse(pcJson);
    if (json)
    {
        pcStatusDecs->iMid = strdup(cJSON_GetObjectItem(json, "mid")->valuestring);
        pcStatusDecs->deviceSn = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        pcStatusDecs->Servicename = strdup(cJSON_GetObjectItem(json, "service")->valuestring);
        pcStatusDecs->zone = strdup(cJSON_GetObjectItem(json, "zone")->valuestring);
        pcStatusDecs->node = strdup(cJSON_GetObjectItem(json, "node")->valuestring);
        // pcStatusDecs->requestID = strdup(cJSON_GetObjectItem(json, "requestId")->valuestring);
        pcStatusDecs->msgTime = strdup(cJSON_GetObjectItem(json, "msgTime")->valuestring);
        pcStatusDecs->deviceID = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);

        if (cJSON_HasObjectItem(json, "params"))
        {
            param = cJSON_GetObjectItem(json, "params");
            IOTA_CONTAINER_CTRL *st_param = pcStatusDecs->param;
            st_param->containerId = strdup(cJSON_GetObjectItem(param, "containerId")->valuestring);
            st_param->containerName = strdup(cJSON_GetObjectItem(param, "containerName")->valuestring);
            st_param->containerHyperv = strdup(cJSON_GetObjectItem(param, "containerHyperv")->valuestring);
            if (cJSON_HasObjectItem(json, "fileId"))
            {
                st_param->fileId = strdup(cJSON_GetObjectItem(param, "fileId")->valuestring);
            }
            else
            {
                st_param->fileId = NULL;
            }

            if (cJSON_HasObjectItem(param, "filename"))
            {
                st_param->filename = strdup(cJSON_GetObjectItem(param, "filename")->valuestring);
            }
            else
            {
                st_param->filename = NULL;
            }
        }
        cJSON_Delete(json);
        return true;
    }
    else
    {
        return false;
    }
}

bool JsonToStruct_ContainerDownload(char *pcJson, ST_IOTA_LOG *pcStatusDecs)
{
    dzlog_info("JsonToStruct_AppDownload start 11");
    cJSON *json = NULL;
    cJSON *param = NULL;
    json = cJSON_Parse(pcJson);
    if (json)
    {
        dzlog_info("JsonToStruct_AppDownload start 22");
        pcStatusDecs->iMid = strdup(cJSON_GetObjectItem(json, "mid")->valuestring);
        dzlog_info("JsonToStruct_AppDownload start 33");
        pcStatusDecs->deviceSn = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        pcStatusDecs->Servicename = strdup(cJSON_GetObjectItem(json, "service")->valuestring);
        pcStatusDecs->zone = strdup(cJSON_GetObjectItem(json, "zone")->valuestring);
        pcStatusDecs->node = strdup(cJSON_GetObjectItem(json, "node")->valuestring);
        // if (cJSON_HasObjectItem(json, "requestId") && strlen(cJSON_GetObjectItem(json, "requestId")->valuestring) > 0)
        //{
        //     pcStatusDecs->requestID = strdup(cJSON_GetObjectItem(json, "requestId")->valuestring);
        // }
        // else
        //{
        //     pcStatusDecs->requestID = NULL;
        // }

        pcStatusDecs->msgTime = strdup(cJSON_GetObjectItem(json, "msgTime")->valuestring);
        pcStatusDecs->deviceID = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);

        if (cJSON_HasObjectItem(json, "params"))
        {
            param = cJSON_GetObjectItem(json, "params");
            IOTA_CON_DOWNLOAD *st_param = pcStatusDecs->param;
            st_param->fileName = strdup(cJSON_GetObjectItem(param, "fileName")->valuestring);
            // st_param->fileLink = strdup(cJSON_GetObjectItem(param, "fileLink")->valuestring);
            st_param->fileId = strdup(cJSON_GetObjectItem(param, "fileId")->valuestring);
            st_param->digestAlgorithm = strdup(cJSON_GetObjectItem(param, "digestAlgorithm")->valuestring);
            st_param->digest = strdup(cJSON_GetObjectItem(param, "digest")->valuestring);
            st_param->fileType = strdup(cJSON_GetObjectItem(param, "fileType")->valuestring);
            st_param->size = cJSON_GetObjectItem(param, "size")->valueint;
        }
        dzlog_info("JsonToStruct_AppDownload start 44");
        cJSON_Delete(json);
        return true;
    }
    else
    {
        return false;
    }
}

bool JsonToStruct_ContainerDownloadProgress(char *pcJson, ST_IOTA_LOG *pcStatusDecs)
{
    cJSON *json = NULL;
    cJSON *param = NULL;
    json = cJSON_Parse(pcJson);
    if (json)
    {
        pcStatusDecs->iMid = strdup(cJSON_GetObjectItem(json, "mid")->valuestring);
        pcStatusDecs->deviceSn = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        pcStatusDecs->Servicename = strdup(cJSON_GetObjectItem(json, "service")->valuestring);
        pcStatusDecs->zone = strdup(cJSON_GetObjectItem(json, "zone")->valuestring);
        pcStatusDecs->node = strdup(cJSON_GetObjectItem(json, "node")->valuestring);
        // pcStatusDecs->requestID = strdup(cJSON_GetObjectItem(json, "requestId")->valuestring);
        pcStatusDecs->msgTime = strdup(cJSON_GetObjectItem(json, "msgTime")->valuestring);
        pcStatusDecs->deviceID = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);

        if (cJSON_HasObjectItem(json, "params"))
        {
            param = cJSON_GetObjectItem(json, "params");
            IOTA_CONTAINER_DOWNLOAD_PROGRESS *st_param = pcStatusDecs->param;
            st_param->fileid = strdup(cJSON_GetObjectItem(param, "fileId")->valuestring);
        }

        cJSON_Delete(json);
        return true;
    }
    else
    {
        return false;
    }
}

bool StructToJson_ContainerDownLoadRes(char **pcJson, ST_IOTA_LOG_RES *pcStatusDecs)
{
    if (pcStatusDecs)
    {
        cJSON *json = NULL;
        cJSON *body = NULL;
        json = cJSON_CreateObject();
        body = cJSON_CreateObject();
        char cTime[128] = {0};
        int ret = systemDate2(cTime);
        // json
        cJSON_AddStringToObject(json, "mid", pcStatusDecs->iMid);
        cJSON_AddNumberToObject(json, "code", pcStatusDecs->code);
        dzlog_info("StructToJson_ContainerDownLoadRes pcStatusDecs->code:%d", pcStatusDecs->code);
        cJSON_AddStringToObject(json, "deviceSn", pcStatusDecs->deviceSn);
        if (pcStatusDecs->replyId != NULL)
        {
            cJSON_AddStringToObject(json, "replyId", pcStatusDecs->replyId);
        }
        cJSON_AddStringToObject(json, "zone", pcStatusDecs->zone);
        cJSON_AddStringToObject(json, "node", pcStatusDecs->node);
        // cJSON_AddStringToObject(json, "requestId", pcStatusDecs->requestID);
        cJSON_AddStringToObject(json, "msgTime", cTime);
        cJSON_AddStringToObject(json, "deviceId", pcStatusDecs->deviceID);

        // body
        IOTA_CONTAINER_DOWNLOAD_PROGRESS *st_body = (IOTA_CONTAINER_DOWNLOAD_PROGRESS *)pcStatusDecs->body;
        cJSON_AddStringToObject(body, "fileId", st_body->fileid);
        cJSON_AddItemToObject(json, "body", body);

        *pcJson = cJSON_PrintUnformatted(json);

        cJSON_Delete(json);
        return true;
    }
    else
    {
        return false;
    }
}

int container_download(char *pJson)
{
    // 分线程
    pthread_t thread;
    pthread_attr_t attr;
    char *psJson = strdup(pJson);
    // 初始化线程属性
    pthread_attr_init(&attr);

    // 将线程设置为分离状态
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    // 创建线程
    pthread_create(&thread, &attr, container_download_pthread, psJson);
    // 销毁线程属性对象
    pthread_attr_destroy(&attr);
    return 0;
}

int container_file_download(char *arg)
{
    // 下载文件
    ProgressInfo *info = (ProgressInfo *)arg;
    int *ret = malloc(sizeof(int));
    char full_filename[200] = {0};
    strcpy(full_filename, info->filename);

    // 从全路径文件名中提取文件名 将之前的全名称改回来
    char *filename = strrchr(full_filename, '/');
    if (filename)
    {
        filename++;
        memset(info->filename, 0, sizeof(info->filename));
        strcpy(info->filename, filename);
    }

    *ret = file_download(full_filename, info);
    info->ret = *ret;
    pthread_exit((void *)ret);
}

/// @brief 下载镜像
/// @param pJson
/// @return
int container_download_pthread(char *pJson)
{
    dzlog_info("下载线程启动");

    ST_IOTA_LOG log;
    IOTA_CON_DOWNLOAD param;
    log.param = &param;
    JsonToStruct_ContainerDownload(pJson, &log);

    char *psJson = NULL;
    char uid[80] = {0};
    GF_GetGUID(uid);
    ST_IOTA_LOG_RES log_res;
    log_res.body = NULL;
    log_res.deviceID = log.deviceID;
    log_res.deviceSn = log.deviceSn;
    log_res.iMid = uid;
    log_res.node = log.node;
    log_res.replyId = log.iMid;

    log_res.zone = log.zone;
    bool isError = false;

    int ret = checkAndCreateDirectory(DOCKER_PATH);
    if (ret == 0)
    {
        log_res.code = 500;
        isError = true;
        dzlog_error("create directory error");
        goto Uerror;
    }
    char filename[300] = {0};
    char filenametemp[300] = {0};
    IOTA_CONTAINER_DOWNLOAD_PROGRESS body; // 参数一样所以借用一下

    char fileid[100] = {0};
    strcpy(fileid, param.fileId);
    body.fileid = fileid;

    log_res.code = 100;
    log_res.body = &body;

    StructToJson_ContainerDownLoadRes(&psJson, &log_res);
    ret = IOTA_SendMqtt("/v1/devices/virtualization/response", psJson, strlen(psJson));
    GF_GetGUID(uid);
    free_s(psJson);
    // 文件名
    // 判断下文件名是否是以tar.gz结尾的
    if (strlen(param.fileName) >= 4)
    {
        if (strcmp(param.fileName + strlen(param.fileName) - 4, ".img") == 0)
        {
            sprintf(filename, "%s", param.fileName);
        }
        else
        {
            sprintf(filename, "%s.img", param.fileName);
        }
    }

    ProgressInfo info;

    strcpy(info.fileid, fileid);
    strcpy(info.md5, param.digest);
    info.filesize = param.size;
    info.ret = 0;

    sprintf(filenametemp, "%s/%s", DOCKER_PATH, filename);
    strcpy(info.filename, filenametemp);
    dzlog_info("filenametemp = %s", filenametemp);
    // 文件下载
    // 分线程
    pthread_t thread;

    // 创建线程
    pthread_create(&thread, NULL, container_file_download, &info);
    // 读取进度
    int retry = 0;
    int progress = 0;
    int *iRet = NULL;
    /*
    while (progress <= 100)
    {

        if (retry > 30)
        {
            dzlog_error("download error time out");
            break;
        }
        sleep(5);
        if (progress == (int)info.downloadProgress)
        {
            retry++;
            dzlog_info("download retry %d", retry);
            continue;
        }
        else
        {
            retry = 0;
        }
        progress = (int)info.downloadProgress;
        dzlog_debug("progress = %d downloadProgress = %f", progress, info.downloadProgress);
        GF_GetGUID(uid);
        send_progress_V3(115, progress, &log_res);
        if (progress == 100)
        {
            break;
        }
    }
    */
    off_t cur_size = 0;
    int flag = 0;
    while (cur_size < param.size)
    { /*
         sleep(5);
         if (retry > 60)
         {
             dzlog_error("download error time out");
             break;
         }
         if (progress == (int)info.downloadProgress)
         {
             retry++;
             dzlog_info("download retry %d", retry);
             continue;
         }
         else
         {
             retry = 0;
         }
         progress = (int)info.downloadProgress;
         dzlog_debug("ota_download progress = %d downloadProgress = %f", progress, info.downloadProgress);
         memset(uid, 0, 64);
         GF_GetGUID(uid);
         log_res.iMid = uid;
         send_progress(115, progress, &log_res);

         if (progress == 100)
         {
             break;
         }*/
        sleep(5);
        struct stat file_inf = {0};

        stat(filenametemp, &file_inf);

        if (cur_size == file_inf.st_size)
        {
            retry++;
            if (retry > 30)
            {
                flag = 1;
                break;
            }
        }
        cur_size = file_inf.st_size;
        dzlog_info("filenametemp[%s], size = %ld", filenametemp, file_inf.st_size);
        progress = 100 * cur_size / param.size;
        ;
        dzlog_debug("ota_download progress = %d", progress);
        memset(uid, 0, 64);
        GF_GetGUID(uid);
        log_res.iMid = uid;
        send_progress_V3(115, progress, &log_res);
    }
    dzlog_info("ota_download 11");

    // 等待线程结束
    pthread_join(thread, (void **)&iRet);

    if (*iRet == -1)
    {
        dzlog_error("下载出错：无法连接到或登录到文件服务器");
        isError = true;
        log_res.code = 520;
        goto Uerror;
    }
    else if (*iRet == -2)
    {
        dzlog_error("下载出错：文件服务器无法查询到该文件");
        isError = true;
        log_res.code = 521;

        goto Uerror;
    }
    else if (*iRet == -3)
    {
        dzlog_error("下载出错：文件下载超时或出错");
        isError = true;
        log_res.code = 522;
        goto Uerror;
    }
    else if (ret == -4)
    {
        dzlog_error("下载出错：没有这个文件或id");
        isError = true;
        log_res.code = 523;
        goto Uerror;
    }
    else
    {
        // 校验sha256
        char hash[SHA256_DIGEST_LENGTH * 2 + 1];
        calculate_file_sha256(filenametemp, hash);
        if (strcmp(hash, param.digest) != 0)
        {
            log_res.code = 420;
            isError = true;
            dzlog_error("Verification error：%s", hash);
            goto Uerror;
        }
        dzlog_info("Download successful:%s", filenametemp);
        log_res.code = 200;
        log_res.body = &body;
        memset(uid, 0, 64);
        GF_GetGUID(uid);
        log_res.iMid = uid;
        dzlog_info("Download log_res.code:%d", log_res.code);
        StructToJson_ContainerDownLoadRes(&psJson, &log_res);
        ret = IOTA_SendMqtt("/v1/devices/virtualization/response", psJson, strlen(psJson));
    }
    //}
Uerror:
    if (isError)
    {
        memset(uid, 0, 64);
        GF_GetGUID(uid);
        log_res.iMid = uid;
        log_res.body = &body;
        StructToJson_ContainerDownLoadRes(&psJson, &log_res);
        ret = IOTA_SendMqtt("/v1/devices/virtualization/response", psJson, strlen(psJson));
    }
Ufree:
    free_s(log.iMid);
    free_s(log.deviceSn);
    free_s(log.deviceID);
    free_s(log.msgTime);
    free_s(log.node);
    // free_s(log->requestID);
    free_s(log.Servicename);
    free_s(log.zone);

    free_s(psJson);

    free_s(param.digest);
    free_s(param.digestAlgorithm);
    free_s(param.fileId);
    free_s(param.fileName);
    free_s(param.fileType);
    dzlog_info("Download successful");
    free_s(pJson);
    free_s(iRet);
    return 0;
}

/**
 * @brief 容器安装
 *
 * @param pJson
 * @return int
 */
int container_install(char *pJson)
{
    dzlog_info("container_install start");
    ST_IOTA_LOG log;
    IOTA_CONTAINER_INFO param;
    log.param = &param;
    JsonToStruct_ContainerInstall(pJson, &log);
    char *psJson = NULL;
    char uid[80] = {0};
    GF_GetGUID(uid);
    ST_IOTA_LOG_RES log_res;

    log_res.deviceID = log.deviceID;
    log_res.deviceSn = log.deviceSn;
    log_res.iMid = uid;
    log_res.node = log.node;
    log_res.replyId = log.iMid;
    // log_res.requestID = log.requestID;
    log_res.zone = log.zone;
    IOTA_CONTAINER_RES body;
    body.containerId = param.containerId;
    body.srcContainerId = NULL;
    log_res.body = &body;
    bool isError = false;
    int ret = 0;
    if (strcmp(param.containerHyperv, "docker") == 0)
    {
        ret = container_docker_install(param);
        if (ret != true)
        {
            log_res.code = ret;
            isError = true;
            goto Uerror;
        }
        else
        {
            log_res.code = 200;
        }
    }
    else if (strcmp(param.containerHyperv, "linux-lxc") == 0)
    {
        /* code */
    }
    StructToJson_ContainerInstallRes(&psJson, &log_res);
    dzlog_info("container_install start 33");
    ret = IOTA_SendMqtt("/v1/devices/virtualization/response", psJson, strlen(psJson));
    dzlog_info("container_install start 44");
Uerror:
    if (isError)
    {
        StructToJson_ContainerInstallRes(&psJson, &log_res);
        ret = IOTA_SendMqtt("/v1/devices/virtualization/response", psJson, strlen(psJson));
    }
Ufree:
    free_s(log.iMid);
    free_s(log.deviceSn);
    free_s(log.deviceID);
    free_s(log.msgTime);
    free_s(log.node);
    // free_s(log.requestID);
    free_s(log.Servicename);
    free_s(log.zone);
    free_s(param.containerId);
    free_s(param.containerName);
    free_s(param.containerHyperv);
    free_s(param.fileId);
    free_s(param.imageName);
    free_s(param.devices);
    free_s(param.volumes);
    free_s(param.ip);

    free_s(psJson);
}

/**
 * @brief 容器克隆
 *
 * @param pJson
 * @return int
 */
int container_clone(char *pJson)
{
    dzlog_info("container_clone start");
    ST_IOTA_LOG log;
    IOTA_CONTAINER_INFO param;
    log.param = &param;
    JsonToStruct_ContainerInstall(pJson, &log);

    char *psJson;
    char uid[80] = {0};
    GF_GetGUID(uid);
    ST_IOTA_LOG_RES log_res;
    log_res.deviceID = log.deviceID;
    log_res.deviceSn = log.deviceSn;
    log_res.iMid = uid;
    log_res.node = log.node;
    log_res.replyId = log.iMid;
    // log_res.requestID = log.requestID;
    log_res.zone = log.zone;
    bool isError = false;
    IOTA_CONTAINER_RES body;
    body.containerId = param.containerId;
    body.srcContainerId = param.srcContainerId;
    log_res.body = &body;

    int ret = 0;

    if (strcmp(param.containerHyperv, "docker") == 0)
    {
        ret = container_docker_clone(param);
        if (ret != true)
        {
            log_res.code = ret;
            isError = true;
            goto Uerror;
        }
        else
        {
            log_res.code = 200;
        }
    }
    else if (strcmp(param.containerHyperv, "linux-lxc") == 0)
    {
        /* code */
    }

    StructToJson_ContainerInstallRes(&psJson, &log_res);
    ret = IOTA_SendMqtt("/v1/devices/virtualization/response", psJson, strlen(psJson));
    dzlog_info("container_install clone finish");
Uerror:
    if (isError)
    {
        StructToJson_ContainerInstallRes(&psJson, &log_res);
        ret = IOTA_SendMqtt("/v1/devices/virtualization/response", psJson, strlen(psJson));
    }
Ufree:
    free_s(log.iMid);
    free_s(log.deviceSn);
    free_s(log.deviceID);
    free_s(log.msgTime);
    free_s(log.node);
    // free_s(log.requestID);
    free_s(log.Servicename);
    free_s(log.zone);
    free_s(param.containerId);
    free_s(param.containerName);
    free_s(param.containerHyperv);
    free_s(param.fileId);
    free_s(param.imageName);
    free_s(param.devices);
    free_s(param.volumes);
    free_s(param.ip);
    free_s(psJson);
}

/**
 * @brief 容器控制（卸载，启动，停止，更新）
 *
 * @param pJson
 * @return int
 */
int container_ctrl(char *pJson, int action)
{
    dzlog_info("container_ctrl start");
    ST_IOTA_LOG log;
    IOTA_CONTAINER_CTRL param;
    log.param = &param;
    JsonToStruct_ContainerCtrl(pJson, &log);

    char *psJson;
    char uid[80] = {0};
    GF_GetGUID(uid);
    ST_IOTA_LOG_RES log_res;
    log_res.deviceID = log.deviceID;
    log_res.deviceSn = log.deviceSn;
    log_res.iMid = uid;
    log_res.node = log.node;
    log_res.replyId = log.iMid;
    // log_res.requestID = log.requestID;
    log_res.zone = log.zone;
    bool isError = false;

    IOTA_CONTAINER_RES body;
    body.containerId = param.containerId;
    body.srcContainerId = NULL;
    log_res.body = &body;
    dzlog_info("container_ctrl start 11 action:%d", action);
    switch (action)
    {
    case 1: // 卸载
        if (strcmp(param.containerHyperv, "docker") == 0)
        {
            int ret = container_docker_uninstall(param);
            if (ret != true)
            {
                log_res.code = ret;
                isError = true;
                goto Uerror;
            }
            else
            {
                log_res.code = 200;
            }
        }
        else if (strcmp(param.containerHyperv, "linux-lxc") == 0)
        {
            /* code */
        }
        break;
    case 2: // 启动
        if (strcmp(param.containerHyperv, "docker") == 0)
        {
            int ret = container_docker_start(param);
            if (ret != true)
            {
                log_res.code = ret;
                isError = true;
                goto Uerror;
            }
            else
            {
                log_res.code = 200;
            }
        }
        else if (strcmp(param.containerHyperv, "linux-lxc") == 0)
        {
            /* code */
        }
        break;
    case 3: // 停止
        if (strcmp(param.containerHyperv, "docker") == 0)
        {
            int ret = container_docker_stop(param);
            if (ret != true)
            {
                log_res.code = ret;
                isError = true;
                goto Uerror;
            }
            else
            {
                log_res.code = 200;
            }
        }
        else if (strcmp(param.containerHyperv, "linux-lxc") == 0)
        {
            /* code */
        }
        break;
    case 4: // 升级
        if (strcmp(param.containerHyperv, "docker") == 0)
        {
            int ret = container_docker_update(param);
            if (ret != true)
            {
                log_res.code = ret;
                isError = true;
                goto Uerror;
            }
            else
            {
                log_res.code = 200;
            }
        }
        else if (strcmp(param.containerHyperv, "linux-lxc") == 0)
        {
            /* code */
        }
    default:
        dzlog_error("不支持的指令");
        break;
    }

    StructToJson_ContainerInstallRes(&psJson, &log_res);
    int ret = IOTA_SendMqtt("/v1/devices/virtualization/response", psJson, strlen(psJson));
Uerror:
    if (isError)
    {
        StructToJson_ContainerInstallRes(&psJson, &log_res);
        ret = IOTA_SendMqtt("/v1/devices/virtualization/response", psJson, strlen(psJson));
    }
Ufree:
    free_s(log.iMid);
    free_s(log.deviceSn);
    free_s(log.deviceID);
    free_s(log.msgTime);
    free_s(log.node);
    // free_s(log.requestID);
    free_s(log.Servicename);
    free_s(log.zone);
    free_s(param.containerId);
    free_s(param.containerName);
    free_s(param.containerHyperv);
    free_s(psJson);
}

int container_command(char *pcJson)
{
    cJSON *json = NULL;
    char cmd[32] = {0};
    json = cJSON_Parse(pcJson);
    if (json)
    {
        strncpy(cmd, cJSON_GetObjectItem(json, "cmd")->valuestring, sizeof(cmd));
        dzlog_info("container_command cmd[%s] ", cmd);
        // 告警规则
        if (strstr(cmd, "actionContainerInstall"))
        {
            container_install(pcJson);
        }
        if (strstr(cmd, "actionContainerUninstall"))
        {
            container_ctrl(pcJson, 1);
        }
        if (strstr(cmd, "actionContainerStart"))
        {
            container_ctrl(pcJson, 2);
        }
        if (strstr(cmd, "actionContainerStop"))
        {
            container_ctrl(pcJson, 3);
        }
        if (strstr(cmd, "actionContainerDownload"))
        {
            container_download(pcJson);
        }
        if (strstr(cmd, "actionContainerClone"))
        {
            container_clone(pcJson);
        }
        if (strstr(cmd, "actionContainerUpgrade"))
        {
            container_ctrl(pcJson, 4);
        }

        cJSON_Delete(json);
    }
    return 0;
}
